﻿using System;
using System.Linq;
using System.Linq.Expressions;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Vasuleg.UIDrive
{
    public abstract class UIDriveMonoBehaviour<T> : MonoBehaviour where T : UIDriveMonoBehaviour<T>
    {
        private T _thisDrive;

        public UIDrive Drive { get; private set; }

        public T ThisDrive
        {
            get
            {
                if (_thisDrive != null)
                {
                    return _thisDrive;
                }

                if (this is not T obj) throw new SystemException("泛型的声明需要同类型");
                Drive ??= new UIDrive(this);
                return _thisDrive = ProxyGeneratorUtils.CreateClassProxyWithTarget(obj, Drive);
            }
        }

        protected virtual void Awake()
        {
            Drive = new UIDrive(this);
            AwakeBinding();
            Drive.Init();
        }


        protected abstract void AwakeBinding();


        protected UIDriveNodeBuilder<TCt> Binding<TCt>(Action<TCt> func)
        {
            return new UIDriveNodeBuilder<TCt>(func.Target as Object, func, Drive);
        }

        protected UIDriveNodeBuilder<Tuple<TCt1, TCt2>> Binding<TCt1, TCt2>(Action<TCt1, TCt2> func)
        {
            return new UIDriveNodeBuilder<Tuple<TCt1, TCt2>>(func.Target as Object, val => func(val.Item1, val.Item2), Drive);
        }

        protected UIDriveNodeBuilder<TCt> Binding<TCt>(Expression<Func<TCt>> func)
        {
            var targetNode = ExpressionUtils.SelectMemberPath(func).FirstOrDefault();
            return targetNode == null ? null : new UIDriveNodeBuilder<TCt>(targetNode.Target as Object, val => targetNode.Set(val), Drive);
        }

        protected virtual void Update()
        {
            Drive.NoticeData();
        }

        private void OnDestroy()
        {
            Drive.Destroy();
            Drive = null;
            _thisDrive = null;
        }
    }
}